package sob

import (
	"bytes"
	"sieve_engine/lib/config"
)

var (
	fTag = config.String("lib.sob.tag", "json", "")
)

func Marshal(v any) ([]byte, error) {
	rt, rv := getReflectType(v)
	n := len(rt.fields)
	d := Data{}
	bb := bytes.NewBuffer(nil)
	for i := 0; i < n; i++ {
		rf := rt.fields[i]
		d.Field = rf.name
		d.Value = rv.Field(rf.i).Interface()
		b, err := d.encode()
		if err != nil {
			return nil, err
		}
		if _, err := bb.Write(b); err != nil {
			return nil, err
		}
	}
	return bb.Bytes(), nil
}

func Unmarshal(data []byte, v any) error {
	rt, rv := getReflectType(v)
	return DecodeFunc(data, func(d Data) error {
		rf, ok := rt.fieldM[d.Field]
		if !ok {
			return nil
		}

		fv := rv.Field(rf.i)
		switch rf.kind {
		case kInt:
			v, err := d.Int64()
			if err != nil {
				return err
			}
			fv.SetInt(v)
		case kUint:
			v, err := d.Uint64()
			if err != nil {
				return err
			}
			fv.SetUint(v)
		case kFloat:
			v, err := d.Float64()
			if err != nil {
				return err
			}
			fv.SetFloat(v)
		case kBool:
			v, err := d.Bool()
			if err != nil {
				return err
			}
			fv.SetBool(v)
		case kString:
			v, err := d.String()
			if err != nil {
				return err
			}
			fv.SetString(v)
		case kBytes:
			v, err := d.Bytes()
			if err != nil {
				return err
			}
			fv.SetBytes(v)
		}
		return nil
	})
}

func Encode(list []*Data) ([]byte, error) {
	bb := bytes.NewBuffer(nil)
	for _, d := range list {
		b, err := d.encode()
		if err != nil {
			return nil, err
		}
		bb.Write(b)
	}
	return bb.Bytes(), nil
}

func Decode(b []byte) ([]*Data, error) {
	list := []*Data{}
	for len(b) > 0 {
		d := &Data{}
		n, err := d.decode(b)
		if err != nil {
			return nil, err
		}
		b = b[n:]
		list = append(list, d)
	}
	return list, nil
}

func DecodeFunc(b []byte, f func(Data) error) error {
	d := Data{}
	for len(b) > 0 {
		n, err := d.decode(b)
		if err != nil {
			return err
		}
		b = b[n:]
		if err := f(d); err != nil {
			return err
		}
	}
	return nil
}
